#include <stdio.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include<string.h>

#define BUF_SIZE 64
#define NAME_SIZE 64
#define NO -1
#define MSG_BODY_SIZE 4

typedef struct filenode{
    char name[NAME_SIZE];//文件名
    int offset;//文件偏移量
    int buffsize;//单次最大信息长度
}filenode,*filelist;

typedef struct my_msg_body{
    int size;//有效信息长度
    char buf[BUF_SIZE];
}my_msg_body,*my_msg_body_list;

typedef struct my_msg{
    int size;//消息体长度
    my_msg_body node;
}my_msg,*my_msg_list;

void my_close(int sockfd,int clientfd,int fd_w){

    if(sockfd > 0){
        close(sockfd);
    }
    if(clientfd > 0){
        close(clientfd);
    }
    if(fd_w > 0){
        close(fd_w);
    }

    return;
}

int find_name(char* name){

    for(int i=0;i<BUF_SIZE;i++){
        if(name[i] == '\0'){
            return 0;
        }
    }

    return -1;
}

int file_size(char* filename){
    int temp =0;
    if(access(filename,F_OK) == 0){
        int fd_r = open(filename,O_RDONLY);
        if(fd_r == 0){
            perror("open err");
            return -1;
        }
        temp=lseek(fd_r,0,SEEK_END);

        close(fd_r);
    }else{
        return 0;
    }
    

    return temp;
}

int my_send(int sockfd,const void* buf,int length){

    int temp=0;
    int ftemp=0;

    while(1){
        
        ftemp=send(sockfd,buf+temp,length - temp,0);//0 阻塞(发送的缓冲区满/网络阻塞);
        if(ftemp == -1){
            perror("my_send err");
            return -1;
        }
        temp+=ftemp;
        if(temp >= length){
            break;
        }
        
    }
    return 0;
}

int my_recv(int sockfd,void* buf,int length){

    int temp=0;
    int ftemp=0;

    while(1){
        
        ftemp=recv(sockfd,buf+temp,length - temp,0);//0 阻塞(发送的缓冲区满/网络阻塞);
        if(ftemp == -1){
            perror("my_send err");
            return -1;
        }
        temp+=ftemp;
        if(ftemp == 0){
            return temp;
        }
        if(temp >= length){
            break;
        }
        
    }
    return temp;
}

int get_file_msg(int sockfd,int clientfd,filelist stat,int* size_file,int statsize){
    if(my_recv(clientfd,stat,statsize) < 0){
        my_close(sockfd,clientfd,NO);
        return -1;
    }
    stat->buffsize=ntohl(stat->buffsize);
    printf("%d\n",stat->buffsize);
    if(stat->buffsize > BUF_SIZE){
        return -1;
    }
    if(find_name(stat->name) == -1){
        my_close(sockfd,clientfd,NO);
        return -1;
    }else{
        *size_file=file_size(stat->name);//获取文件大小
        printf("%d\n",*size_file);
        if(*size_file < 0){
            perror("read size err");
            my_close(sockfd,clientfd,NO);
            return -1;
        }else{
            *size_file=htonl(*size_file);
        }
    }
    if(my_send(clientfd,size_file,sizeof(int)) == -1){ //send 不一定会一次全部发送完，分多次发送完
        perror("send err");
        my_close(sockfd,clientfd,NO);
        return -1;
    }
    return 0;
}

int my_send_serialization(int sockfd,int clientfd,filelist stat,my_msg_body_list node,int nodesize){

    int fd_r = open(stat->name,O_RDONLY);
    if(fd_r == -1){
        perror("open err");
        my_close(sockfd,clientfd,NO);
        return -1;
    }
    lseek(fd_r,stat->offset,SEEK_SET);

    int temp = 0;
    // printf("%p,%p",&(node->size),node->buf);
    while(1){
        memset(node->buf,0,nodesize-MSG_BODY_SIZE);
        temp =read(fd_r,node->buf,stat->buffsize);//读取buffsize个字节
        if(temp == -1){
            perror("read err");
            my_close(sockfd,clientfd,fd_r);
            return -1;
        }
        if(temp == 0){
            printf("send complete\n");
            sleep(2);//等待客户端关闭
            break;
        }
        node->size=htonl(temp);
    
        if(my_send(clientfd,node,temp+MSG_BODY_SIZE) == -1){ //send 不一定会一次全部发送完，分多次发送完
            perror("send err");
            break;
        }
        
    }
    close(fd_r);
    return 0;
}

int my_send_Sticky_packs(int sockfd,int clientfd,filelist stat,my_msg_list bodynode){
    int nodesize=sizeof(bodynode->node);
    if(nodesize < stat->buffsize+MSG_BODY_SIZE){//如果client请求发送的消息体大于sever的消息体
        return -1;
    }
    bodynode->size=htonl(stat->buffsize+MSG_BODY_SIZE);
    if(my_send(clientfd,&(bodynode->size),sizeof(int)) == -1){ //send 不一定会一次全部发送完，分多次发送完
        perror("send err");
        return -1;
    }

    if(my_send_serialization(sockfd,clientfd,stat,&(bodynode->node),nodesize) == -1){
        return -1;
    }

    return 0;
}

int main(void){
    int sockfd = socket(AF_INET,SOCK_STREAM,0);//ipv4,tcp
    if(sockfd == -1){
        perror("sock err");
        return -1;
    }
    //服务器地址:IP 端口号
    struct sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_port =htons(8888);
    
    addr.sin_addr.s_addr=INADDR_ANY;//本地的ip都可以
    printf("IP=%s\n",inet_ntoa(addr.sin_addr));
    socklen_t addrlen= sizeof(addr);
    //绑定
    if(bind(sockfd,(struct sockaddr*)&addr,addrlen) == -1){
        perror("bind err");
        my_close(sockfd,NO,NO);
        return -1;
    }

    //监听
    if(listen(sockfd,5) == -1){
        perror("listen err");
        my_close(sockfd,NO,NO);
        return -1;
    }
    printf("waiting client connect!\n");

    //响应连接
    struct sockaddr_in client_addr;
    socklen_t clientlen;
    int clientfd=accept(sockfd,NULL,NULL);
    if(clientfd < 0){
        perror("accept err");
        my_close(sockfd,NO,NO);
        return -1;
    }
    printf("new connect comming\n");
    
    //获取文件信息
    filenode stat;
    int size_file=0;
    memset(&stat,0,sizeof(stat));
    if(get_file_msg(sockfd,clientfd,&stat,&size_file,sizeof(stat)) == -1){
        my_close(sockfd,clientfd,NO);
        return -1;
    }
    

    //收发数据
    stat.offset=ntohl(stat.offset);
   
    my_msg bodynode;
    if(my_send_Sticky_packs(sockfd,clientfd,&stat,&bodynode) == -1){
        my_close(sockfd,clientfd,NO);
        return -1;
    }
    


    //关闭
    my_close(sockfd,clientfd,NO);


    return 0;
}
